package com.cv.infra.framework.dynamicThreadPool.config;

import com.cv.infra.framework.dynamicThreadPool.core.DynamicQueue;
import com.cv.infra.service.dynamicThreadPool.DynamicThreadPoolService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 动态线程池配置 - 视频转码专用
 *
 * @author Charles_XDXD
 */
@Slf4j
@Configuration
public class DynamicThreadPoolConfiguration {

    @Lazy
    @Resource
    private DynamicThreadPoolService dynamicThreadPoolService;

    /**
     * 队列默认容量
     */
    public static final int DEFAULT_QUEUE_CAPACITY = 100;

    /**
     * 保持活跃时间（默认单位：秒）
     */
    public static final long DEFAULT_KEEP_ALIVE_TIME = 60;

    /**
     * 核心线程数
     */
    public static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();

    /**
     * 最大线程数
     */
    public static final int MAX_POOL_SIZE = (int) (CORE_POOL_SIZE * 1.5);

    /**
     * 拒绝策略（默认：任务不被丢弃且希望由调用线程处理的情况）
     */
    public static final RejectedExecutionHandler DEFAULT_REJECT_POLICY = new ThreadPoolExecutor.CallerRunsPolicy();

    /**
     * 线程池
     */
    private final ThreadPoolExecutor dynamicThreadPool;

    /**
     * 初始化动态线程池
     */
    @Autowired
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    public DynamicThreadPoolConfiguration() {
        log.info("[DynamicThreadPool] 启动动态线程池");

        // 因为无法确定转码的处理时间和高并发的情况，因此选用 LinkedBlockingQueue 来作为阻塞队列
        this.dynamicThreadPool = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                DEFAULT_KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new DynamicQueue<>(DEFAULT_QUEUE_CAPACITY),
                DEFAULT_REJECT_POLICY
        ) {
            /**
             * 执行前后，分别检查/调节线程池状态，从而达到伪实时监控调节的效果
             */
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                super.beforeExecute(t, r);
                dynamicThreadPoolService.listenDynamicThreadPool();
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                dynamicThreadPoolService.listenDynamicThreadPool();
            }
        };

        log.info("[DynamicThreadPool] 动态线程池启动成功");
    }

    /**
     * 销毁时，关闭线程池
     */
    @PreDestroy
    public void shutdownVideoTranscodingExecutor() {
        log.info("[DynamicThreadPool] 开始关闭动态线程池");

        if (!dynamicThreadPool.isShutdown()) {
            dynamicThreadPool.shutdown();

            try {
                // 等待所有任务完成
                while (!dynamicThreadPool.awaitTermination(120, TimeUnit.SECONDS)) {
                    log.info("[DynamicThreadPool] 当前线程池中仍存在任务未完成，待任务完成后关闭");
                }
            } catch (InterruptedException e) {
                log.error("线程池关闭过程中发生中断异常", e);
                dynamicThreadPool.shutdownNow();
            }
        }

        log.info("[DynamicThreadPool] 动态线程池已成功关闭");
    }


    /**
     * 注入动态线程池
     *
     * @return 动态线程池实例
     */
    @Bean
    public ThreadPoolExecutor dynamicThreadPool() {
        return dynamicThreadPool;
    }

}
